package com.example.learnquartz.quartz;

// import com.gamer.um.quartz.configure.SchedulerJob;
// import com.gamer.um.quartz.jobs.MonitorCronJob;

import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @version v1.0
 * @description:
 * @author: 47 on 2020/4/9 11:37
 */
@Component
public class SchedulerManager {

    private final static Logger logger = LoggerFactory.getLogger(SchedulerManager.class);


    @Autowired
    private Scheduler scheduler;

    /**
     * 激活任务
     * @param schedulerJob
     */
    public void activeJob(SchedulerJob schedulerJob){
        JobKey jobKey = JobKey.jobKey(schedulerJob.getName(), schedulerJob.getGroup());
        try {
            if (scheduler.checkExists(jobKey) && !MonitorCronJob.JOB_NAME.equals(schedulerJob.getName())) {
                updateJob(schedulerJob);
            }else {
                createJob(schedulerJob);
            }
        } catch (SchedulerException e) {
            logger.error("activeJob {}", e);
        }
    }

    /**
     * 创建任务并加入调度
     * @param schedulerJob
     */
    public void createJob(SchedulerJob schedulerJob){
        JobKey jobKey = JobKey.jobKey(schedulerJob.getName(), schedulerJob.getGroup());
        try {
            if (scheduler.checkExists(jobKey)) {
                return;
            }
            Class<?> clazz = Class.forName(schedulerJob.getJobClass());
            JobDetail jobDetail = getJobDetail(schedulerJob, (Class<Job>) clazz);
            Trigger cronTrigger = getCronTrigger(schedulerJob);
            //加入调度器
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (ClassNotFoundException | SchedulerException e) {
            logger.error("createJob {}", e);
        }
    }

    /**
     * 更新任务触发器
     * @param schedulerJob
     */
    public void updateJob(SchedulerJob schedulerJob){
        TriggerKey triggerKey = TriggerKey.triggerKey(schedulerJob.getName(), schedulerJob.getGroup());
        try {
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            JobKey jobKey = trigger.getJobKey();
            //查询cron
            String oldCron = ((CronTrigger)trigger).getCronExpression();
            //没有变化则返回
            if (oldCron.equals(schedulerJob.getCron())){
                return;
            }
            Trigger cronTrigger = getCronTrigger(schedulerJob);
            //加入调度器
            scheduler.rescheduleJob(triggerKey, cronTrigger);
        } catch (SchedulerException e) {
            logger.error("updateJob {}", e);
        }
    }

    public void deleteJobs(List<JobKey> jobKeys) {
        try {
            scheduler.deleteJobs(jobKeys);
        } catch (SchedulerException e) {
            logger.error("deleteJobs {}", e);
        }
    }

    /**
     * 创建任务
     * @param schedulerJob
     * @param clazz
     * @return
     */
    private JobDetail getJobDetail(SchedulerJob schedulerJob, Class<Job> clazz) {
        return JobBuilder.newJob()
                .ofType(clazz)
                .withIdentity(schedulerJob.getName(), schedulerJob.getGroup())
                .withDescription(schedulerJob.getDesc())
                .build();
    }

    /**
     * 创建触发器
     * @param schedulerJob
     * @return
     */
    private Trigger getCronTrigger(SchedulerJob schedulerJob) {
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(schedulerJob.getCron());
        if (!MonitorCronJob.JOB_NAME.equals(schedulerJob.getName())){
            //任务错过执行策略，以错过的第一个频率时间立刻开始执行，重做错过的所有频率周期后，当下一次触发频率发生时间大于当前时间后，再按照正常的Cron频率依次执行
            cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
        }
        return TriggerBuilder.newTrigger()
                .withIdentity(schedulerJob.getName(), schedulerJob.getGroup())
                .withDescription(schedulerJob.getDesc())
                .withSchedule(cronScheduleBuilder)
                .build();
    }

}
